Facebook Hacker Cup 2016 Round 1 C. Yachtzee(期望)

题意:

$给定初始金钱[A, B]均匀分布,A, B\le 10^9$
$现在购买一个东西,分成N\le 10^5部分,每部分价值为C_i\le 10^9$
$会不停的按顺序购买N个部分直到不能购买为止$
$问剩余钱数的期望$

分析:

$根据期望的线性可加性,我们可以求[0, B]的期望减去[0, A]的期望$
$然后对于[0, x]的期望,对C_i求个前缀和,对于每个区间[C_{i-1}, C_i]$
$L_i=C_i-C_{i-1},如果完全覆盖那么它的贡献是L_i\cdot\frac{L_i}{2}$
$周期cycle = x/C_n,剩下的left=x\%C_n,计算方式相同$
$那么总贡献E=cycle\cdot L_i\cdot\frac{L_i}{2}+E_{left},期望E’=\frac{E_B-E_A}{B-A}$

代码:

//
//  Created by TaoSama on 2016-01-17
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, A, B;
typedef long long LL;
LL a[N];

LL calc(int x) {
    LL ret = 0;
    LL cycle = x / a[n], left = x % a[n];
    for(int i = 1; i <= n; ++i)
        ret += (a[i] - a[i - 1]) * (a[i] - a[i - 1]);
    ret *= cycle;
    int k = lower_bound(a + 1, a + n + 1, left) - a;
    for(int i = 1; i <= k; ++i)
        ret += (min(a[i], left) - a[i - 1]) * (min(a[i], left) - a[i - 1]);
    return ret;
}

int main() {
#ifdef LOCAL
    freopen("yachtzee.txt", "r", stdin);
    freopen("yachtzee_out.txt", "w", stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d%d", &n, &A, &B);
        for(int i = 1; i <= n; ++i) {
            scanf("%lld", a + i);
            a[i] += a[i - 1];
        }
        double ans = 1.0 * (calc(B) - calc(A)) / 2 / (B - A);
        static int kase = 0;
        printf("Case #%d: %.9f\n", ++kase, ans);
    }
    return 0;
}